#include "commons.h"

char serialPortString[] = {0x55, 0x00, 0x00, 0xAA};
unsigned int period; //pwm
unsigned int timerCounterI = 0, timerCounterJ = 0;
unsigned int ones, tens, hunds, thous, ten_thous, hund_thous, thous_thous;

void __attribute__((__interrupt__, no_auto_psv)) _PWMInterrupt(void) {
    IFS2bits.PWMIF = 0;
}

void __attribute__((__interrupt__, no_auto_psv)) _T2Interrupt(void) {
    IFS0bits.T2IF = 0;
    timerCounterI++;
    timerCounterJ++;
}

void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void) {
    IFS0bits.T3IF = 0;
}


void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void) {
    IFS1bits.U2RXIF = 0;
    ErrorUartSend();
}

void __attribute__((interrupt, no_auto_psv)) _U2TXInterrupt(void) {
    IFS1bits.U2TXIF = 0; 
}


void Init_LCD(void) {
    DelayNmSecNew(15);

    //  LATD &= 0xFF00;
    DATA &= 0xFF00; // lcd.c use this
    //DATA = 0x00;  old definition
    RW = 0; // R/W state set low
    RS = 0; // RS state set low
    E = 0; // E state set low
    /* set data and control pins to outputs */
    TRIS_DATA &= 0xFF00; // lcd.c use this
    // 	TRIS_DATA = 0x00;  old definition
    RW_TRIS = 0; // RW pin set as output
    RS_TRIS = 0; // RS pin set as output
    E_TRIS = 0; // E pin set as output


    /* 1st LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;		//old definition
    //DATA = 0x38;		//old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNmSecNew(5); //5ms

    /* 2nd LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;
    //DATA = 0x38;
    Nop();
    Nop();
    Nop();
    //    E = 0;	//old definition
    E = 1; // lcd.c use this
    DelayNuSec(200); //200us

    /* 3rd LCD initialization sequence */
    DATA &= 0xFF00; // lcd.c use this
    DATA |= 0x0038; // lcd.c use this
    //DATA = 0x00;	//old definition
    //DATA = 0x38;	//old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNuSec(200); //200us

    lcd_cmd(0x38); //8bit, 5*8, 1/16DUTY
    lcd_cmd(0x06); //AC auto add 1??
    lcd_cmd(0x0c); //display on

}

void Init_PWM(void) {
    unsigned int config; //??PWM?????
    unsigned int sptime; //?????SEVTCMP ????????????
    unsigned int config1; //??PWM??????PTCON?
    unsigned int config2; //????PWMCON1?????
    unsigned int config3; //??????????????????PWMCON2???
    //unsigned int dutycycle=0x03ff;		//?????????????(??????????)
    config = (PWM_INT_EN & PWM_FLTA_DIS_INT & PWM_INT_PR1
            & PWM_FLTA_INT_PR0
            & PWM_FLTB_DIS_INT & PWM_FLTB_INT_PR0); //PWM????;??A????;PWM?????1;??A?????0;??B????;??B?????0
    ConfigIntMCPWM(config); //????PWM????/??;????????


    SetMCPWMDeadTimeAssignment(PWM_DTS1A_UA & //??PWM???????DTCON2?:1H????????????1L??????????
            PWM_DTS1I_UB & PWM_DTS2A_UA & //???A??;1H????????????1L?????????????B??
            PWM_DTS2I_UB);

    SetMCPWMDeadTimeGeneration(PWM_DTBPS8 &
            PWM_DTA54 & PWM_DTAPS8 & PWM_DTB54); //??PWM??????????DTCON1?:????B????1:8;????A????54;
    //????A????1:8;????B????54;
    period = 0x1F00; //??PTPER???????(???????????)
    //period = 0x6168; //20Hz
    sptime = 0x0; //??SEVTCMP?????
    config1 = (PWM_EN & PWM_IDLE_STOP & PWM_OP_SCALE16 &
            PWM_IPCLK_SCALE16 & PWM_MOD_FREE); //PWM??;PWM???????;??????1:16;??????1:16;??????

    config2 = (PWM_PEN4L & PWM_PEN3H & PWM_PEN2H & PWM_PEN1H &
            PWM_PEN4H & PWM_PEN3L & PWM_PEN2L & PWM_PEN1L &
            PWM_MOD1_IND & PWM_MOD2_IND & PWM_MOD3_IND &
            PWM_MOD4_IND); //??PWM1f?PWM2?PWM3?PWM4????I/O

    config3 = (PWM_SEVOPS1 & PWM_OSYNC_PWM & PWM_UEN); //????????1:1;?????PWM????;PWM????
    OpenMCPWM(period, sptime, config1, config2, config3); //?PTMR;SEVTCMP;PTCON;PWMCON1;PWMCON2
}

void InitTMR3(void) {
    TMR3 = 0;
    PR3 = 65535;
    IFS0bits.T3IF = 0;
    IEC0bits.T3IE = 1;
    T3CON = 0x8020;
    ConfigIntTimer3(T3_INT_PRIOR_4 & T3_INT_ON);
}


void InitTMR(void) {
    TMR2 = 0; // clear timer 2
    PR2 = TMR_RATE / 1000; //1ms
    IFS0bits.T2IF = 0; // clr interrupt flag
    IEC0bits.T2IE = 1; // set interrupt enable bit
    T2CON = 0x8020; //1:64 prescale, open TMR2
    ConfigIntTimer2(T2_INT_PRIOR_5 & T2_INT_ON);
    InitTMR3();
}


void SetupPorts(void) {
    PORTA = 0x0000; //RA14 15?1
    TRISA = 0x3FFF;
    PORTB = 0x0000;
    TRISB = 0x0FFF; //  0 is out, 1 is in, RB12-15 are for BNC ports, output
    PORTC = 0x0000;
    TRISC = 0xFFF5; //  RC1 3??
    PORTD = 0x0000;
    TRISD = 0xFF0F; // FROM UART FILE
    //TRISD = 0x3FFF;   //  ORIGINAL , LCD, RD14 and RD15 are BNC ports, output
    PORTE = 0x0000; //
    TRISE = 0xFEFF; // RE8??
    PORTF = 0x0000;
    TRISF = 0xFF33; // RF2 3 6 7??
    PORTG = 0x0000;
    TRISG = 0xFC36; // RG0 3 6 7 8 9 ??
}

void lcd_cmd(char cmd) {
    RS = 0;
    RW = 0;
    Nop();
    Nop();
    DATA &= 0xFF00; // lcd.c use this
    DATA |= cmd; // lcd.c use this
    //      DATA = 0x00;	// old definition
    //      DATA = cmd;		// old definition
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    DelayNmSecNew(5); //5ms
}

void lcd_data(char data) {
    RS = 1;
    RW = 0;
    Nop();
    Nop();
    DATA &= 0xFF00; // lcd.c use this
    DATA |= data; // lcd.c use this
    E = 1;
    Nop();
    Nop();
    Nop();
    E = 0;
    RS = 0;
    DelayNuSec(400);
}

void puts_lcd(unsigned char *data, unsigned char count) {
    while (count) {
        lcd_data(*data++);
        count--;
    }
}

void LCD_set_xy(unsigned int x, unsigned int y) //??LCD????????????x?y   ?????????X:1-16?Y:1-2
{
    unsigned char address;
    if (y == 1) {
        address = 0x80 - 1 + x;
    } else {
        address = 0xc0 - 1 + x;
    }
    lcd_cmd(address);
}

void counts_dispose(unsigned int counter) {
    ones = 0;
    tens = 0;
    hunds = 0;
    thous = 0;
    ten_thous = 0;
    hund_thous = 0;
    thous_thous = 0;
    while (counter > 0) {
        if (counter > 9999) {
            ten_thous++;
            counter -= 10000;
        } else if (counter > 999) {
            thous++;
            counter -= 1000;
        } else if (counter > 99) {
            hunds++;
            counter -= 100;
        } else if (counter > 9) {
            tens++;
            counter -= 10;
        } else {
            ones++;
            counter--;

        }
    };

    ones += 0x30;
    tens += 0x30;
    hunds += 0x30;
    thous += 0x30;
    ten_thous += 0x30;
    hund_thous += 0x30;
    thous_thous += 0x30;
}
//
//void beep(void) {
//    PORTDbits.RD11 = 1;
//    DelayNmSec(300);
//    PORTDbits.RD11 = 0;
//}


// definition is same with previous board

void Valve_ON(unsigned int N, unsigned int rate) //1L--4H??????1--?4
{
    switch (N) {
        case 1: PORTGbits.RG0 = 1;
            PDC1 = rate;
            //	UartSend[1] = SpWater_sweet;
            break; // Sweet ON
        case 2: PORTCbits.RC1 = 1;
            PDC1 = rate;
            //	UartSend[1] = SpOdor_A;
            break; // ValveA ON
        case 3: PORTCbits.RC3 = 1;
            PDC2 = rate;
            //	UartSend[1] = SpOdor_B;
            break; // ValveB ON
        case 4: PORTGbits.RG6 = 1;
            PDC2 = rate;
            //	UartSend[1] = SpWater_bitter;
            break; // Bitter ON
        case 5: PORTGbits.RG7 = 1;
            PDC3 = rate;
            break;
        case 6: PORTGbits.RG9 = 1;
            PDC3 = rate;
            break;
        case 7: PORTEbits.RE8 = 1;
            PDC4 = rate;
            break;
        case 8: PORTGbits.RG8 = 1;
            PDC4 = rate;
            break;
    }
    // UartSend[2] = 1;
    // Puts_UART2((unsigned char*)&UartSend[0], sizeof(UartSend));
}

void Valve_OFF(unsigned int N) {
    switch (N) {
            // ?????????????BNC???output
            // case 1: PORTGbits.RG0=0; Digt_out(4,2); break; // Sweet OFF, BNC4=1 for 2 ms
            // case 2: PORTCbits.RC1=0; Digt_out(2,2); break; // ValveA OFF, BNC2=1 for 2 ms
            // case 3: PORTCbits.RC3=0; Digt_out(3,2); break; // ValveB OFF, BNC3=1 for 2 ms
            // case 4: PORTGbits.RG6=0; Digt_out(4,4); break; // Bitter OFF, BNC4=1 for 4 ms

        case 1: PORTGbits.RG0 = 0;
            //UartSend[1] = SpWater_sweet;
            break; // Sweet OFF
        case 2: PORTCbits.RC1 = 0;
            //UartSend[1] = SpOdor_A;
            break; // ValveA OFF
        case 3: PORTCbits.RC3 = 0;
            //UartSend[1] = SpOdor_B;
            break; // ValveB OFF
        case 4: PORTGbits.RG6 = 0;
            //UartSend[1] = SpWater_bitter;
            break; // Bitter OFF

        case 5: PORTGbits.RG7 = 0;
            break;
        case 6: PORTGbits.RG9 = 0;
            break;
        case 7: PORTEbits.RE8 = 0;
            break;
        case 8: PORTGbits.RG8 = 0;
            break;
    }
    // UartSend[2] = 0;
    // Puts_UART2((unsigned char*)&UartSend[0], sizeof(UartSend));

}

//-------------DELAY-----------------------------
// definition is same with previous board
//
//void DelayNmSec(unsigned int N) {
//    unsigned int j;
//    while (N--)
//        for (j = 0; j < MILLISEC; j++);
//}

// definition is same with previous board

void DelayNuSec(unsigned int N) {
    unsigned int j;
    while (N--)
        for (j = 0; j < uSEC; j++);

}

void DelayNmSecNew(unsigned int N) {
    timerCounterJ = 0;
    while (timerCounterJ < N) {
        Nop();
    }
}

/*****************************************************/
void Digt_out(unsigned int Nchan, unsigned int Duration) // digital output in 1
{
    switch (Nchan) {

            /*	case 1:     //A
                            Out1 = 1;
                            DelayNuSec(400*Duration);
                            Out1 = 0;; //
                            break;  */


        case 1: //A
            Out1 = 1;
            DelayNuSec(400 * Duration);
            Out1 = 0;
            ; //
            break;

        case 2: // light on during delay
            Out2 = 1;
            DelayNmSecNew(1000 * Duration);

            // DelayNuSec(400*Duration);

            Out2 = 0; //
            break;

        case 3: //AB
            Out3 = 1;
            DelayNuSec(400 * Duration);
            Out3 = 0;
            ; //
            break;
        case 4: //AB
            Out4 = 1;
            DelayNuSec(400 * Duration);
            Out4 = 0;
            ; //
            break;
        case 5: //AB
            Out5 = 1;
            DelayNuSec(400 * Duration);
            Out5 = 0;
            ; //
            break;
        case 6: //AB
            Out6 = 1;
            DelayNuSec(400 * Duration);
            Out6 = 0;
            ; //
            break;
            //        case 7: //AB
            //            Out7 = 1;
            //            DelayNuSec(400 * Duration);
            //            Out7 = 0;
            //            ; //
            //            break;
            //        case 8: //AB
            //            Out8 = 1;
            //            DelayNuSec(400 * Duration);
            //            Out8 = 0;
            //            ; //
            //            break;
        default:
            break;
    }
}

void InitUART2(void) {
    unsigned int baudvalue;
    unsigned int U2MODEvalue;
    unsigned int U2STAvalue;
    CloseUART2(); 
    ConfigIntUART2(UART_RX_INT_EN & UART_RX_INT_PR6 &
            UART_TX_INT_DIS & UART_TX_INT_PR2);
    U2MODEvalue = UART_EN & UART_IDLE_CON &
            UART_DIS_WAKE & UART_DIS_LOOPBACK &
            UART_EN_ABAUD & UART_NO_PAR_8BIT&
            UART_1STOPBIT; 
    U2STAvalue = UART_INT_TX_BUF_EMPTY &
            UART_TX_PIN_NORMAL &
            UART_TX_ENABLE & UART_INT_RX_CHAR &
            UART_ADR_DETECT_DIS &
            UART_RX_OVERRUN_CLEAR; 
    baudvalue = ((FCY / 16) / BAUDRATE) - 1; 
    OpenUART2(U2MODEvalue, U2STAvalue, baudvalue); 
}

void UART2PutChar(unsigned char Ch) {
    // wait for empty buffer
    while (BusyUART2());
    U2TXREG = Ch;
}

void Puts_UART2(unsigned char *data, unsigned char count) {
    while (count) {
        UART2PutChar(*data++);
        count--;
    }
}

// output is the pulse in serial port

void localSendOnce(int thisSp, int thisValue) {
    serialPortString[1] = thisSp;
    serialPortString[2] = thisValue;
    Puts_UART2((unsigned char*) &serialPortString[0], sizeof (serialPortString));

}

void ErrorUartSend(void) {
    // UartSend is a global variable, just send it again without chaning anything
    Puts_UART2((unsigned char*) &serialPortString[0], sizeof (serialPortString));
}

unsigned int getFuncNumber(int targetDigits, char* input) {

    int bitSet[targetDigits];
    int bitValue[targetDigits];
    unsigned int n;
    int iter;
    int iter1;

    for (iter = 0; iter < targetDigits; iter++) {
        bitSet[iter] = 0;
        bitValue[iter] = -6;
    }

    home_clr();
    LCDWriteString(input);

    for (iter = 0; iter < targetDigits; iter++) {
        while (!bitSet[iter]) {
            if (S1) {
                bitValue[iter] = 1;
                bitSet[iter] = 1;
            } else if (S2) {
                bitValue[iter] = 2;
                bitSet[iter] = 1;
            } else if (S3) {
                bitValue[iter] = 3;
                bitSet[iter] = 1;
            } else if (S4) {
                bitValue[iter] = 4;
                bitSet[iter] = 1;
            } else if (S5) {
                bitValue[iter] = 5;
                bitSet[iter] = 1;
            }
        }
        home_clr();
        LCDWriteString(input);
        line_2();
        for (iter1 = 0; iter1 < targetDigits; iter1++) {
            lcd_data(bitValue[iter1] + 0x30);
        }
        DelayNmSecNew(500);
    }
    n = 0;
    for (iter1 = 0; iter1 < targetDigits; iter1++) {
        n = n * 10 + bitValue[iter1];
    }
    return n;
}

void LCDWriteString(char* s) {
    int length = strlen(s) > 16 ? 16 : strlen(s);
    int iter;
    for (iter = 0; iter < length; iter++) {
        lcd_data((unsigned) s[iter]);
    }
}
